/*
 * DOES NOT USE BUILT-IN DETECTION FUNCTION
 *
  alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (msg:"WEB-CLIENT Microsoft Visio could allow remote code execution"; flowbits:isset,file.visio; flow:to_client,established; content:"|c9 00|"; reference:cve,2009-0097; reference:url,technet.microsoft.com/en-us/security/bulletin/MS09-005; metadata:policy balanced-ips drop, policy security-ips drop, service http; classtype:attempted-user;)
 */
/*
 * Use at your own risk.
 *
 * Copyright (C) 2005-2008 Sourcefire, Inc.
 * 
 * This file is autogenerated via rules2c, by Brian Caswell <bmc@sourcefire.com>
 */

#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"

//#define DEBUG
#ifdef DEBUG
#define DEBUG_WRAP(code) code
#else
#define DEBUG_WRAP(code)
#endif

/* declare detection functions */
int rule15298eval(void *p);

/* declare rule data structures */
/* precompile the stuff that needs pre-compiled */
/* flowbits:isset "file.visio"; */
static FlowBitsInfo rule15298flowbits0 =
{
    "file.visio",
    FLOWBIT_ISSET,
    0,
};

static RuleOption rule15298option0 =
{
    OPTION_TYPE_FLOWBIT,
    {
        &rule15298flowbits0
    }
};
/* flow:established, to_client; */
static FlowFlags rule15298flow1 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule15298option1 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule15298flow1
    }
};
// content:"|C9 00|", depth 0; 
static ContentInfo rule15298content2 = 
{
    (uint8_t *) "|C9 00|", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_BUF_NORMALIZED|CONTENT_RELATIVE, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule15298option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule15298content2
    }
};

/* references for sid 15298 */
/* reference: cve "2009-0097"; */
static RuleReference rule15298ref1 = 
{
    "cve", /* type */
    "2009-0097" /* value */
};

/* reference: url "technet.microsoft.com/en-us/security/bulletin/MS09-005"; */
static RuleReference rule15298ref2 = 
{
    "url", /* type */
    "technet.microsoft.com/en-us/security/bulletin/MS09-005" /* value */
};

static RuleReference *rule15298refs[] =
{
    &rule15298ref1,
    &rule15298ref2,
    NULL
};
/* metadata for sid 15298 */
/* metadata:service http, policy balanced-ips drop, policy security-ips drop; */
static RuleMetaData rule15298service1 = 
{
    "service http"
};
//
//
//static RuleMetaData rule15298policy1 = 
//{
//    "policy balanced-ips drop"
//};
//
//static RuleMetaData rule15298policy2 = 
//{
//    "policy security-ips drop"
//};

static RuleMetaData rule15298policy3 = 
{
    "policy max-detect-ips drop"
};

static RuleMetaData *rule15298metadata[] =
{
    &rule15298service1,
//    &rule15298policy1,
//    &rule15298policy2,
    &rule15298policy3,
    NULL
};
RuleOption *rule15298options[] =
{
    &rule15298option0,
    &rule15298option1,
    &rule15298option2,
    NULL
};

Rule rule15298 = {
   
   /* rule header, akin to => tcp any any -> any any               */{
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "$HTTP_PORTS", /* SRCPORT   */
   
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
   
       "any", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid (HARDCODED!!!) */
       15298, /* sigid */
       12, /* revision */
   
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "FILE-OFFICE Microsoft Visio could allow remote code execution",     /* message */
       rule15298refs /* ptr to references */
       ,rule15298metadata
   },
   rule15298options, /* ptr to rule options */
   &rule15298eval, /* use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
int rule15298eval(void *p) {
    const uint8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const uint8_t *end_of_payload = 0;
    const uint8_t *cursor_temp = 0;
    
    int32_t object_size = 0;
    uint16_t num_elements = 0;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flowbits:isset "file.visio";
    if (processFlowbits(p, rule15298options[0]->option_u.flowBit) > 0) {
            // flow:established, to_client;
        if (checkFlow(p, rule15298options[1]->option_u.flowFlags) > 0 ) {

            /* Note that this rule detects only visio file version <= 5.0 */
          
            if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_payload) <= 0)
                  return RULE_NOMATCH;
          
            // content:"|C9 00|", CONTENT_BUF_NORMALIZED|CONTENT_RELATIVE
            while (contentMatch(p, rule15298options[2]->option_u.content, &cursor_normal) > 0)
            {
                if(cursor_normal + 12 > end_of_payload)
                   return RULE_NOMATCH;

                // if byte DepthLevel > 3 or USHORT ChildCount != 0, find the next |C9 00| occurrence
                if ((*(cursor_normal + 2) > 3) || (*(cursor_normal + 4) != 0 || *(cursor_normal + 5) != 0))
                  continue;

                cursor_temp = cursor_normal; // use a temporary pointer not to change the origianl cursor_normal

                cursor_temp += 6;
                object_size = read_little_32(cursor_temp);    /* read objectSize in PACKED_OBJECT_HEADER */
                DEBUG_WRAP(printf("object_size = %x\n", object_size));
        
                if (object_size > 0)
                {
                    cursor_temp += 4;
                    num_elements = read_little_16(cursor_temp);    /* read numElement in SORTED_OBJ_ID_TABLE */
                    DEBUG_WRAP(printf("num_elements = %x\n", num_elements));

                    if (object_size < num_elements)
                    {
                            return RULE_MATCH;
                    }
                }                                                         
            }
        }
    }
    return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule15298,
    NULL
};
*/
